package util;


import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 身份证工具类
 *
 * @author hezhao on 2017年7月25日 下午3:02:59
 */
public class IdCardUtil {
    private static final Logger logger = LoggerFactory.getLogger(IdCardUtil.class);

    /**
     * 中国公民身份证号码长度。
     */
    public static final int CHINA_ID_LENGTH = 18;
    

    public static Map<String, String> cityCodes = new HashMap<String, String>();


    static {
        cityCodes.put("11", "北京");
        cityCodes.put("12", "天津");
        cityCodes.put("13", "河北");
        cityCodes.put("14", "山西");
        cityCodes.put("15", "内蒙古");
        cityCodes.put("21", "辽宁");
        cityCodes.put("22", "吉林");
        cityCodes.put("23", "黑龙江");
        cityCodes.put("31", "上海");
        cityCodes.put("32", "江苏");
        cityCodes.put("33", "浙江");
        cityCodes.put("34", "安徽");
        cityCodes.put("35", "福建");
        cityCodes.put("36", "江西");
        cityCodes.put("37", "山东");
        cityCodes.put("41", "河南");
        cityCodes.put("42", "湖北");
        cityCodes.put("43", "湖南");
        cityCodes.put("44", "广东");
        cityCodes.put("45", "广西");
        cityCodes.put("46", "海南");
        cityCodes.put("50", "重庆");
        cityCodes.put("51", "四川");
        cityCodes.put("52", "贵州");
        cityCodes.put("53", "云南");
        cityCodes.put("54", "西藏");
        cityCodes.put("61", "陕西");
        cityCodes.put("62", "甘肃");
        cityCodes.put("63", "青海");
        cityCodes.put("64", "宁夏");
        cityCodes.put("65", "新疆");
        cityCodes.put("71", "台湾");
        cityCodes.put("81", "香港");
        cityCodes.put("82", "澳门");
        cityCodes.put("91", "国外");

    }


    /**
     * 验证身份编码是否合法
     *
     * @param idCard
     * @return
     */
    public static boolean validateIdCard(String idCard) {
        System.out.println(validateIDCardByRegex(idCard));
        System.out.println(verify(idCard));
        System.out.println(getProvinceByIdCard(idCard));

        return validateIDCardByRegex(idCard) && verify(idCard) && getProvinceByIdCard(idCard) != null ? true : false;
        
    }


    /**
     * 根据正则校验身份证
     *
     * @param idCard
     * @return
     */
    private static boolean validateIDCardByRegex(String idCard) {

        if (StringUtils.isEmpty(idCard) || idCard.length() != CHINA_ID_LENGTH) {

            return false;
        }

        return idCard.matches("^\\d{6}" +
                "((19|20)\\d{2})" +//年
                "(0[1-9]|1[0-2])" +//月
                "(0[1-9]|[1-2][0-9]|3[0-1])" +// 日
                "\\d{3}([0-9]|x|X)$"//后四位
        );

    }


    /**
     * 身份证最后一位的校验算法
     *
     * @param idCard
     * @return
     */
    private static boolean verify(String idCard) {
        char[] id = idCard.toCharArray();

        int sum = 0;
        int w[] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
        char[] ch = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
        for (int i = 0; i < id.length - 1; i++) {
            sum += (id[i] - '0') * w[i];
        }
        int c = sum % 11;
        char code = ch[c];
        char last = id[id.length - 1];
        last = last == 'x' ? 'X' : last;
        return last == code;
    }


  


    /**
     * 根据身份编号获取年龄
     *
     * @param idCard
     * @return
     */
    public static int getAgeByIdCard(String idCard) {
        String year = idCard.substring(6, 10);
        Calendar cal = Calendar.getInstance();
        int iCurrYear = cal.get(Calendar.YEAR);
        int iAge = iCurrYear - Integer.valueOf(year);
        return iAge;
    }


    /**
     * 根据身份编号获取生日
     *
     * @param idCard
     * @return 生日(yyyy-MM-dd)
     */
    public static String getBirthByIdCard1(String idCard) {
        return idCard.substring(6, 10) + "-" + idCard.substring(10, 12) + "-" + idCard.substring(12, 14);
    }


    /**
     * 根据身份编号获取生日
     *
     * @param idCard
     * @return 生日(yyyy年MM月dd)
     */
    public static Date getBirthByIdCard(String idCard) throws Exception {
        return DateUtils.parseDate(idCard.substring(6, 14),"yyyyMMdd") ;
    }
    /**
     * 根据身份编号获取生日
     *
     * @param idCard
     * @return 生日(yyyy年MM月dd)
     */
    public static String getBirthByIdCard2(String idCard) {
        return idCard.substring(6, 10) + "-" + idCard.substring(10, 12) + "-" + idCard.substring(12, 14);
    }


    /**
     * 根据身份编号获取性别
     *
     * @param idCard
     * @return 性别(1-男，0-女)
     */
    public static int getGenderByIdCard(String idCard) {

        String sCardNum = idCard.substring(16, 17);
        if (Integer.parseInt(sCardNum) % 2 != 0) {
            return 1;
        } else {
            return 0;
        }

    }

    /**
     * 根据身份编号获取户籍省份
     *
     * @param idCard
     * @return
     */
    public static String getProvinceByIdCard(String idCard) {

        return cityCodes.get(idCard.substring(0, 2));

    }


    /**
     * 根据身份编号获取 出生年份
     *
     * @param idCard
     * @return
     */
    public static int getYearByIdCard(String idCard) {
        return Integer.valueOf(idCard.substring(6, 10));
    }

    /**
     * 根据身份编号获取 出生月份
     *
     * @param idCard
     * @return
     */
    public static int getMonthByIdCard(String idCard) {

        return Integer.valueOf(idCard.substring(10, 12));
    }

    /**
     * 根据身份编号获取 出生 日份
     *
     * @param idCard
     * @return
     */
    public static int getDateByIdCard(String idCard) {

        return Integer.valueOf(idCard.substring(12, 14));
    }


    /**
     * 根据身份证号，自动获取对应的星座
     *
     * @param idCard
     * @return 星座
     */
    public static String getConstellationByIdCard(String idCard) {

        int month = getMonthByIdCard(idCard);
        int day = getDateByIdCard(idCard);
        String strValue = "";

        if ((month == 1 && day >= 20) || (month == 2 && day <= 18)) {
            strValue = "水瓶座";
        } else if ((month == 2 && day >= 19) || (month == 3 && day <= 20)) {
            strValue = "双鱼座";
        } else if ((month == 3 && day > 20) || (month == 4 && day <= 19)) {
            strValue = "白羊座";
        } else if ((month == 4 && day >= 20) || (month == 5 && day <= 20)) {
            strValue = "金牛座";
        } else if ((month == 5 && day >= 21) || (month == 6 && day <= 21)) {
            strValue = "双子座";
        } else if ((month == 6 && day > 21) || (month == 7 && day <= 22)) {
            strValue = "巨蟹座";
        } else if ((month == 7 && day > 22) || (month == 8 && day <= 22)) {
            strValue = "狮子座";
        } else if ((month == 8 && day >= 23) || (month == 9 && day <= 22)) {
            strValue = "处女座";
        } else if ((month == 9 && day >= 23) || (month == 10 && day <= 23)) {
            strValue = "天秤座";
        } else if ((month == 10 && day > 23) || (month == 11 && day <= 22)) {
            strValue = "天蝎座";
        } else if ((month == 11 && day > 22) || (month == 12 && day <= 21)) {
            strValue = "射手座";
        } else if ((month == 12 && day > 21) || (month == 1 && day <= 19)) {
            strValue = "魔羯座";
        }
        return strValue;
    }


    /**
     * 根据身份证号，自动获取对应的生肖
     *
     * @param idCard 身份证号码
     * @return 生肖
     */
    public static String getZodiacByIdCard(String idCard) {

        String sSX[] = {"猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗"};
        int year = getYearByIdCard(idCard);
        int end = 3;
        int x = (year - end) % 12;

        return sSX[x];
    }




    public static void main(String[] args)  throws Exception{
        String idCard = "34242219930323451X";
        System.out.println(getGenderByIdCard(idCard));
        System.out.println(getBirthByIdCard(idCard));
        System.out.println(getZodiacByIdCard(idCard));
        System.out.println(getConstellationByIdCard(idCard));
        System.out.println(getProvinceByIdCard(idCard));
        System.out.println(validateIdCard(idCard));
        System.out.println(getMonthByIdCard(idCard));
        System.out.println(getAgeByIdCard(idCard));
        System.out.println(getDateByIdCard(idCard));
        System.out.println(getYearByIdCard(idCard));
    }
}


